Repository navigation
fix: stop an unmatched repository inheriting a global identity - #12
Conversation
|
Verdict: changes requested Reviewed at The core of this change is right and I verified both halves independently. With the keys moved out, a repository matching no rule and no A matched repository still resolves: The second half holds up. Removing just the unconditional block from So the unconditional block is load bearing, exactly as the commit message claims. The destructive path is also well guarded. Ten attempts to make
What stops this from being an approve is the profile the keys land in, and one data loss case. Blocker
Should
Nit
Scope
Tests have real teeth. I reverted the code behind three of them in a detached scratch copy and each Next round through the |
ebedba9 to
d6d489b
Compare
|
Verdict: changes requested Round two, at
Round one's findings
Tests have teeth. Each fix reverted on its own in a detached, source only scratch copy fails its The error prefix cleanup is clean: all eleven sites keep their own context, the caller supplies Blocker
Should
Nit
Rounds are exhausted on this pull request, so the blocker needs a human to pick up rather than |
The key was written only into the profile files, which are reached through an includeIf, so it never applied to a repository no rule matches. That is the only repository it was meant to protect. It is written unconditionally at the top of the managed include file now. Refs #8
Position agnostic, unlike the existing ordering check: a key set directly in the global config wins for every unmatched repository wherever it sits. Refs #8
The edit goes through yaml.Node rather than a struct round trip, so a hand written configuration keeps the comments its author put there. Refs #8
init names every identity key the global config sets directly, says why it defeats the per remote identity, and moves them into a dedicated profile only when asked. The default never moves and never reads stdin, and both files are backed up before a write. Refs #8
Nothing enforced the promise that the keys never land in an existing profile or in the defaultProfile. Targeting the default made every unmatched repository inherit the leaked identity again, the exact bug the move exists to fix, and a deliberate value was overwritten in silence either way. The updated configuration is also written and validated before anything is removed from the global config, so a file that would not load no longer leaves the user with no identity at all, and a multi document file is refused by name rather than truncated. Refs #8
A bare "profiles:" key decodes to a null scalar, and appending to a scalar is dropped on marshal, so init reported success, removed the global identity and wrote nothing. The identity survived only in the backup. A null child becomes a real mapping now, and any other shape is refused rather than coerced. Beyond the cause, the rendered bytes are parsed back and checked to carry the keys before anything is removed, so a write that does not contain what it claimed can no longer be followed by a removal. A symlinked configuration is resolved and written through, keeping a dotfiles checkout intact, and the validation file no longer has a predictable name. Refs #8
d6d489b to
ce2b3f4
Compare
|
Verdict: approve Round three, scoped to round two's finding list and what the rework introduced. Round two's findings
New findingsShould
Nit
Nothing in the diff outside round two's list looks wrong: the |
What
internal/gitconfigwritesuser.useConfigOnlyunconditionally at the top of the managedinclude file, not only inside the profile files.
internal/gitfinds identity keys the global config sets directly, wherever they sit, and canremove them.
internal/configcan add keys to a profile throughyaml.Node, so a hand writtenconfiguration keeps its comments.
cmd/gitcdinitreports those keys, says why they defeat the per remote identity, and movesthem into a dedicated profile only when asked.
Why
enough on its own:
useConfigOnlywas written only into the profile files, which are reachedthrough an
includeIf, so it never applied to a repository no rule matches, which is the onlyrepository it was meant to protect. Both halves are needed for the guarantee to hold, and the
second was found by probing git rather than from the issue text.
whichever profile happens to exist would silently overwrite a key someone set on purpose, and
writing into
defaultProfilewould defeat the protection being added, since an unmatchedrepository is supposed to receive nothing.
Verification
task checkexit 0 after the rebase ontomain.HOMEwith a leaked global identity and a hand written~/.gitcd.yaml:gitcd initreports both keys, names the profile they belong in, and moves nothing. Theglobal config still carries them.
gitcd init --move-identity=yesmoves them into profileglobal, removes them from theglobal config, backs up both files, and says plainly that the new profile is not applied
automatically.
fatal: no email was given and auto-detection is disabled. Before this change the samecommit succeeded under the leaked identity.
made to move keys by accident.
Risk
--move-identity=askprompts on stderr and reads one line from stdin. There is no terminaldetection, because that needs a dependency this repository does not carry, so interactivity is
opt in rather than detected. A closed or empty stdin resolves to no.
~/.gitcd.yamlpreserves comments but reflows the file: indentation is normalised andblank lines between top level sections are dropped. The content is correct and the comments
survive, but a hand written file does not come back byte identical.
initprints its report on stdout. Whether that counts as the command's result, whichAGENTS.mdreserves stdout for, is worth a second opinion.Closes #8
Open in [code]smith · Need help on this PR? Tag
@codesmith-botwith what you need.